Raw code available at SW_Morphology

Study Design

Setup

Load all packages

# libraries
library(car)
library(coxme)
library(dplyr)
library(ehahelper)
library(ggeffects)
library(ggplot2)
library(ggpubr)
library(ggthemes)
library(lme4)
library(lmerTest)
library(readr)
library(sjmisc)
library(survival)

sessionInfo()

sessionInfo()
R version 4.3.0 (2023-04-21)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.4

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib 
LAPACK: /Library/Frameworks/R.framework/Versions/4.3-arm64/Resources/lib/libRlapack.dylib;  LAPACK version 3.11.0

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

time zone: Europe/London
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] sjmisc_2.8.9       readr_2.1.4        ggthemes_4.2.4     ggpubr_0.6.0      
 [5] ggplot2_3.4.2      ggeffects_1.2.2    ehahelper_0.3.9999 dplyr_1.1.2       
 [9] coxme_2.2-18.1     survival_3.5-5     car_3.1-2          carData_3.0-5     
[13] bdsmatrix_1.3-6    lmerTest_3.1-3     lme4_1.1-33        Matrix_1.5-4      

loaded via a namespace (and not attached):
 [1] utf8_1.2.3          generics_0.1.3      tidyr_1.3.0         rstatix_0.7.2      
 [5] stringi_1.7.12      lattice_0.21-8      hms_1.1.3           magrittr_2.0.3     
 [9] grid_4.3.0          backports_1.4.1     gridExtra_2.3       purrr_1.0.1        
[13] fansi_1.0.4         scales_1.2.1        eha_2.10.3          numDeriv_2016.8-1.1
[17] abind_1.4-5         cli_3.6.1           rlang_1.1.1         cowplot_1.1.1      
[21] munsell_0.5.0       splines_4.3.0       withr_2.5.0         tools_4.3.0        
[25] tzdb_0.3.0          nloptr_2.0.3        ggsignif_0.6.4      minqa_1.2.5        
[29] colorspace_2.1-0    sjlabelled_1.2.0    boot_1.3-28.1       broom_1.0.4        
[33] vctrs_0.6.2         R6_2.5.1            lifecycle_1.0.3     stringr_1.5.0      
[37] MASS_7.3-60         insight_0.19.1      pkgconfig_2.0.3     pillar_1.9.0       
[41] gtable_0.3.3        glue_1.6.2          Rcpp_1.0.10         xfun_0.39          
[45] tibble_3.2.1        tidyselect_1.2.0    rstudioapi_0.14     knitr_1.42         
[49] nlme_3.1-162        compiler_4.3.0     

Data files

Data file ADD_I is available on the github page.

Morphometric and Island Comparison

Preparing Data

# read the data file "ADD_I"
ADD_I <- read_csv("Tables/ADD_I.csv", col_types = cols(Island = col_factor(levels = c("CN","AR", "CE", "DS", "FR"))))
# create the earliest born individuals on each island
Isfy <- ADD_I %>% select(founderyear,Island) %>% filter(!duplicated(Island))
# create a data frame with means and sd of each morphometric
ADD_mean <- ADD_I %>% group_by(Island,BirthYear) %>% summarise(RTsd = sd(RightTarsus,na.rm=TRUE),WLsd = sd(WingLength,na.rm=TRUE),BMsd = sd(BodyMass,na.rm=TRUE),HBsd=sd(HeadBill,na.rm=TRUE),RightTarsus=mean(RightTarsus,na.rm=TRUE),WingLength=mean(WingLength,na.rm=TRUE),BodyMass=mean(BodyMass,na.rm=TRUE),HeadBill=mean(HeadBill,na.rm=TRUE))

Linear Mixed Effect Models

Tarsus Length

####RightTarsus ----
IRTlmer <- lmer(RightTarsus ~  Island*fYear + Sex + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IRTlmer)

#predicting the model 
IRTlmerdata <- ggpredict(IRTlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,RightTarsus=predicted,Island=group,Sex=facet)
IRTlmerdata2 <- merge(IRTlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 25)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11))%>% mutate(BirthYear = fYear + founderyear) %>% group_by(Island,BirthYear) %>% summarise(RightTarsus = mean(RightTarsus, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model (shown as ggarrange below)
IRTmod <- ggplot(IRTlmerdata2, aes(x = BirthYear, y = RightTarsus, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=RightTarsus,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=RightTarsus-RTsd,ymax=RightTarsus+RTsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "loess", se = FALSE) + 
  geom_ribbon(aes(ymin=RightTarsus-std.error,ymax=RightTarsus+std.error),alpha=0.5) +
  labs(x = "Birth Year", y= "Tarsus Length (mm)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Body Mass

#### Body Mass ----
IBMlmer <- lmer(BodyMass ~  Island*fYear + Sex  + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IBMlmer)

#predicting the model
IBMlmerdata <- ggpredict(IBMlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,BodyMass=predicted,Island=group,Sex=facet)
IBMlmerdata2 <- merge(IBMlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 25)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11))%>% mutate(BirthYear = fYear + founderyear)  %>% group_by(Island,BirthYear) %>% summarise(BodyMass = mean(BodyMass, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model
IBMmod <- ggplot(IBMlmerdata2, aes(x = BirthYear, y = BodyMass, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=BodyMass,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=BodyMass-BMsd,ymax=BodyMass+BMsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "lm", se = FALSE) + 
  geom_ribbon(aes(ymin=BodyMass-std.error,ymax=BodyMass+std.error),alpha=0.5) +
  labs(x = "Birth Year", y= "Body Mass (g)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Wing Length

#### Wing Length ----
IWLlmer <- lmer(WingLength ~  Island*fYear + Sex + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IWLlmer)

#predicting the model
IWLlmerdata <- ggpredict(IWLlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,WingLength=predicted,Island=group,Sex=facet)
IWLlmerdata2 <- merge(IWLlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 25)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11)) %>% mutate(BirthYear = fYear + founderyear) %>% group_by(Island,BirthYear)%>% summarise(WingLength = mean(WingLength, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model
IWLmod <- ggplot(IWLlmerdata2, aes(x = BirthYear, y = WingLength, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=WingLength,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=WingLength-WLsd,ymax=WingLength+WLsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "lm", se = FALSE) + 
  geom_ribbon(aes(ymin=WingLength-std.error,ymax=WingLength+std.error),alpha=0.5) +
  labs(x = "Birth Year", y= "Wing Length (mm)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Head + Bill Length

#### Head + Bill ----
IHBlmer <- lmer(HeadBill ~  Island*fYear + Sex  + (1|Observer) + (1|Ageclass) + (1|BirdID), data = ADD_I)
summary(IHBlmer)

#predicting the model
IHBlmerdata <- ggpredict(IHBlmer,terms=c("fYear [all]","Island","Sex")) %>% rename(fYear=x,HeadBill=predicted,Island=group,SexEstimate=facet)
IHBlmerdata2 <- merge(IHBlmerdata,Isfy,by="Island", all.x=TRUE) %>% filter(!(Island== "AR" & fYear > 22)) %>% filter(!(Island== "CE" & fYear > 25)) %>% filter(!(Island== "DS" & fYear > 18)) %>% filter(!(Island== "FR" & fYear > 11))%>% mutate(BirthYear = fYear + founderyear)%>% group_by(Island,BirthYear)%>% summarise(HeadBill = mean(HeadBill, na.rm=TRUE), std.error = mean(std.error, na.rm=TRUE))

#plotting the model
IHBmod <- ggplot(IHBlmerdata2, aes(x = BirthYear, y = HeadBill, fill = Island)) + 
  geom_point(data = ADD_mean, mapping=aes(x=BirthYear,y=HeadBill,colour=Island), size = 2) +
  geom_errorbar(data=ADD_mean,aes(ymin=HeadBill-HBsd,ymax=HeadBill+HBsd, colour=Island),alpha=0.7) +
  geom_smooth(aes(colour = Island),method = "lm", se = FALSE) + 
  geom_ribbon(aes(ymin=HeadBill-std.error,ymax=HeadBill+std.error),alpha=0.25) +
  labs(x = "Birth Year", y= "Head + Bill Length (mm)") +
  xlim(1990,2022) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind() + scale_fill_colorblind()

Arrange and plot

Imods <- ggarrange(IRTmod,IBMmod,IWLmod,IHBmod, common.legend=TRUE, labels = c("A","B","C","D"))
Imods

Lifespan and Reproduction

Preparing data

# make a non-redundant data set for lifespan and reproduction
ADD_Real <- ADD_I %>% filter(Island == "CN") %>% group_by(BirdID) %>% mutate(across(c(RightTarsus,BodyMass,WingLength,HeadBill),mean, na.rm=TRUE)) %>% filter(!duplicated(BirdID)) %>% select(RightTarsus,BodyMass,WingLength,HeadBill,BirdID,SexEstimate,BirthYear,Lifespan,SurvStatus,ReproductiveOutput) %>% mutate(SexEstimate = as.factor(SexEstimate))
# filter for missing values
ADD_tidy <- ADD_Real %>% filter(!is.na(RightTarsus) & !is.na(BodyMass)  & !is.na(WingLength)  & !is.na(HeadBill) & !is.na(SexEstimate)  & !is.na(Lifespan) ) %>% mutate(BodyCondition = BodyMass/RightTarsus) %>% mutate(SexEstimate = as.factor(SexEstimate))

Survival analysis with coxme

Model comparisons

###Lifespan analysis with coxme----

lscox0 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus+ BodyMass + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox1 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus+ poly(BodyMass,2) + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox2 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus*poly(BodyMass,2) + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox3 <- coxme(Surv(Lifespan,SurvStatus) ~ poly(BodyCondition,2) + WingLength + HeadBill +SexEstimate + (1|BirthYear), data= ADD_tidy)
lscox4 <- coxme(Surv(Lifespan,SurvStatus) ~ RightTarsus+ poly(BodyMass,2)*SexEstimate + WingLength + HeadBill + (1|BirthYear), data= ADD_tidy)

AIC(lscox0,lscox1,lscox2,lscox3,lscox4) # lscox4 best
BIC(lscox0,lscox1,lscox2,lscox3,lscox4) # lscox4 best
# lscox4 was selected based on the best AIC and BIC values

lscox4

Predicting and plotting coxme

####predict lifespan----
ADD_round <- ADD_Real %>%mutate(across(c(RightTarsus, BodyMass, HeadBill, WingLength), round, 0)) %>% distinct(RightTarsus, BodyMass, HeadBill, WingLength,SexEstimate) %>% filter(!is.na(RightTarsus) & !is.na(BodyMass)  & !is.na(WingLength)  & !is.na(HeadBill) & !is.na(SexEstimate))
ADD_end <- bind_rows(ADD_tidy,ADD_round)
rs <- predict_coxme(lscox4,newdata = ADD_end,type="risk", se.fit=TRUE)
rsend <- ADD_end %>% add_columns(rr = rs$fit[,1], se.fit = rs$se.fit[,1])
ADD_tail <- rsend %>% tail(nrow(ADD_round)) %>% mutate(SexEstimate = as.factor(SexEstimate)) %>% group_by(BodyMass,SexEstimate) %>% summarise(mean_rr=mean(rr),mean_se.fit=mean(se.fit))

# plotting coxme
coxmeplot <- ggplot(ADD_tail,aes(x=BodyMass,y=mean_rr)) + 
  geom_line(aes(colour=SexEstimate)) +
  geom_ribbon(aes(fill=SexEstimate,ymin=mean_rr-mean_se.fit,ymax=mean_rr+mean_se.fit), alpha = 0.25) + 
  labs(x = "Body Mass (g)", y = "Mortality Risk Score") +
  guides(fill=guide_legend(title="Sex"), colour=guide_legend(title="Sex")) +
  theme_tufte(base_size = 15, base_family = "Arial") + 
  scale_color_colorblind(labels = c("Female", "Male")) +
  scale_fill_colorblind(labels = c("Female", "Male"))

Reproductive Output using GLM

Model comparisons

###Reproduction glm----
ROglmF <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength + HeadBill  ,data = ADD_tidy, family = "poisson")
ROglmR <- glm(ReproductiveOutput ~ poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm0 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength + HeadBill  + Lifespan + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm1 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength  + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm2 <- glm(ReproductiveOutput ~ poly(RightTarsus,2)+ BodyMass + WingLength + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm3 <- glm(ReproductiveOutput ~ RightTarsus+ poly(BodyMass,2) + WingLength + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm4 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + poly(WingLength,2) + HeadBill  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")
ROglm5 <- glm(ReproductiveOutput ~ RightTarsus+ BodyMass + WingLength + poly(HeadBill,2)  + poly(Lifespan,2) + SexEstimate + BirthYear,data = ADD_tidy, family = "poisson")

AIC(ROglmF,ROglmR,ROglm0,ROglm1,ROglm2,ROglm3,ROglm4,ROglm5) # ROglm4 slightly better than ROglm1 second
BIC(ROglmF,ROglmR,ROglm0,ROglm1,ROglm2,ROglm3,ROglm4,ROglm5) # ROglm1 best 
#ROglm1 was selected based on AIC and BIC scores
vif(ROglm1)

summary(ROglm1)

Predicting and plotting GLM

####predict reproduction----
# grouping variables for glm plot
ROplotdata <- ADD_tidy %>% mutate(BodyMass = case_when(BodyMass > 16.5 ~ "16.5", BodyMass < 14.5 ~ "14.5",BodyMass < 16.5 & BodyMass > 14.5 ~ "15.5")) %>% filter(!is.na(BodyMass))

# predicting glm 
ROglmdat <- ggpredict(ROglm1, terms = c("Lifespan","BodyMass")) %>% rename(Lifespan=x,ReproductiveOutput=predicted,BodyMass=group)

#plotting glm
ROglmplot <- ggplot(ROglmdat, aes(x=Lifespan,y=ReproductiveOutput)) + 
  geom_point(data = ROplotdata, mapping=aes(x=Lifespan,y=ReproductiveOutput,colour=BodyMass),position="jitter") +
  geom_smooth(aes(colour=BodyMass), se = FALSE) + 
  geom_ribbon(aes(ymin=conf.low,ymax=conf.high,fill=BodyMass), alpha = 0.25) +
  labs(x = "Lifespan (years)", y= "Total Number of Offspring") +
  theme_tufte(base_size = 15, base_family = "Arial") +
  scale_color_colorblind() + scale_fill_colorblind()

Arrange and plot

fitplot <- ggarrange(coxmeplot,ROglmplot,  labels = c("A","B"))
fitplot

Time taken to run the whole script

Acknowledgment

Thank you for going through the code and supporting open research. This paper would not have been possible without all authors contributing towards it. Massive thanks to everyone that has shared their excitement for this paper.

LS0tCnRpdGxlOiAnTW9ycGhvbG9naWNhbCBkaXZlcmdlbmNlIGluIGZyYWdtZW50ZWQgcG9wdWxhdGlvbnM6IE5vIGV2aWRlbmNlIG9mIGZpdG5lc3MKICBiZW5lZml0JwphdXRob3I6ICJDaHVlbiBaLiBMZWUsIFRob21hcyBKLiBCcm93biwgRGF2aWQgUy4gUmljaGFyZHNvbiIKZGF0ZTogIjIwMjMtMDYtMDEiCm91dHB1dDoKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6CiAgICAgIGNvbGxhcHNlZDogVFJVRQogICAgdGhlbWU6IHlldGkKLS0tCgpSYXcgY29kZSBhdmFpbGFibGUgYXQgW1NXX01vcnBob2xvZ3ldKGh0dHBzOi8vZ2l0aHViLmNvbS9DaHVlbi1MZWUvU1dfTW9ycGhvbG9neSkKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsb3V0LndpZHRoID0gJzEwMCUnLCAgZmlnLmFsaWduID0gImNlbnRlciIsIG1lc3NhZ2UgPSBGQUxTRSwgd2FybmluZyA9IEZBTFNFLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLndpZHRoID0xMCwgZXJyb3IgPSBUUlVFKQpgYGAKCiMjIFN0dWR5IERlc2lnbgoKIVtdKEltYWdlcy9TdHVkeURlc2lnbi5wbmcpCgojIFNldHVwCgojIyBMb2FkIGFsbCBwYWNrYWdlcwoKYGBge3IgbGlicmFyaWVzLCBlY2hvID0gVCwgbWVzc2FnZSA9IEZBTFNFfQojIGxpYnJhcmllcwpsaWJyYXJ5KGNhcikKbGlicmFyeShjb3htZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShlaGFoZWxwZXIpCmxpYnJhcnkoZ2dlZmZlY3RzKQpsaWJyYXJ5KGdncGxvdDIpCmxpYnJhcnkoZ2dwdWJyKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KGxtZTQpCmxpYnJhcnkobG1lclRlc3QpCmxpYnJhcnkocmVhZHIpCmxpYnJhcnkoc2ptaXNjKQpsaWJyYXJ5KHN1cnZpdmFsKQpgYGAKCiMjIyBzZXNzaW9uSW5mbygpCgo8ZGV0YWlscz4KCmBgYHtyfQpzZXNzaW9uSW5mbygpCmBgYAoKPC9kZXRhaWxzPgoKYGBge3IgaW5jbHVkZT1GQUxTRX0Kc3RhcnRfdGltZTwtU3lzLnRpbWUoKQpgYGAKCiMjIERhdGEgZmlsZXMKCkRhdGEgZmlsZSBbQUREX0ldKGh0dHBzOi8vZ2l0aHViLmNvbS9DaHVlbi1MZWUvQ2h1ZW4tTGVlLmdpdGh1Yi5pby9ibG9iL2Y0OTY4YTAwMWQzNGM1MjJhOTEyYmEzYTM1MGJiMDU4ZDUwYTQ3NzUvcGFnZXMvMjAyMy9TZXljaGVsbGVzV2FyYmxlci9UYWJsZXMvQUREX0kuY3N2KSBpcyBhdmFpbGFibGUgb24gdGhlIGdpdGh1YiBwYWdlLgoKIyBNb3JwaG9tZXRyaWMgYW5kIElzbGFuZCBDb21wYXJpc29uCgojIyBQcmVwYXJpbmcgRGF0YQoKYGBge3IgRGF0YSB0YWJsZXMgZm9yIGlzbGFuZH0KIyByZWFkIHRoZSBkYXRhIGZpbGUgIkFERF9JIgpBRERfSSA8LSByZWFkX2NzdigiVGFibGVzL0FERF9JLmNzdiIsIGNvbF90eXBlcyA9IGNvbHMoSXNsYW5kID0gY29sX2ZhY3RvcihsZXZlbHMgPSBjKCJDTiIsIkFSIiwgIkNFIiwgIkRTIiwgIkZSIikpKSkKIyBjcmVhdGUgdGhlIGVhcmxpZXN0IGJvcm4gaW5kaXZpZHVhbHMgb24gZWFjaCBpc2xhbmQKSXNmeSA8LSBBRERfSSAlPiUgc2VsZWN0KGZvdW5kZXJ5ZWFyLElzbGFuZCkgJT4lIGZpbHRlcighZHVwbGljYXRlZChJc2xhbmQpKQojIGNyZWF0ZSBhIGRhdGEgZnJhbWUgd2l0aCBtZWFucyBhbmQgc2Qgb2YgZWFjaCBtb3JwaG9tZXRyaWMKQUREX21lYW4gPC0gQUREX0kgJT4lIGdyb3VwX2J5KElzbGFuZCxCaXJ0aFllYXIpICU+JSBzdW1tYXJpc2UoUlRzZCA9IHNkKFJpZ2h0VGFyc3VzLG5hLnJtPVRSVUUpLFdMc2QgPSBzZChXaW5nTGVuZ3RoLG5hLnJtPVRSVUUpLEJNc2QgPSBzZChCb2R5TWFzcyxuYS5ybT1UUlVFKSxIQnNkPXNkKEhlYWRCaWxsLG5hLnJtPVRSVUUpLFJpZ2h0VGFyc3VzPW1lYW4oUmlnaHRUYXJzdXMsbmEucm09VFJVRSksV2luZ0xlbmd0aD1tZWFuKFdpbmdMZW5ndGgsbmEucm09VFJVRSksQm9keU1hc3M9bWVhbihCb2R5TWFzcyxuYS5ybT1UUlVFKSxIZWFkQmlsbD1tZWFuKEhlYWRCaWxsLG5hLnJtPVRSVUUpKQpgYGAKCiMjIExpbmVhciBNaXhlZCBFZmZlY3QgTW9kZWxzCgojIyMgVGFyc3VzIExlbmd0aAoKYGBge3IgcnQsIG1lc3NhZ2U9RkFMU0V9CiMjIyNSaWdodFRhcnN1cyAtLS0tCklSVGxtZXIgPC0gbG1lcihSaWdodFRhcnN1cyB+ICBJc2xhbmQqZlllYXIgKyBTZXggKyAoMXxPYnNlcnZlcikgKyAoMXxBZ2VjbGFzcykgKyAoMXxCaXJkSUQpLCBkYXRhID0gQUREX0kpCnN1bW1hcnkoSVJUbG1lcikKCiNwcmVkaWN0aW5nIHRoZSBtb2RlbCAKSVJUbG1lcmRhdGEgPC0gZ2dwcmVkaWN0KElSVGxtZXIsdGVybXM9YygiZlllYXIgW2FsbF0iLCJJc2xhbmQiLCJTZXgiKSkgJT4lIHJlbmFtZShmWWVhcj14LFJpZ2h0VGFyc3VzPXByZWRpY3RlZCxJc2xhbmQ9Z3JvdXAsU2V4PWZhY2V0KQpJUlRsbWVyZGF0YTIgPC0gbWVyZ2UoSVJUbG1lcmRhdGEsSXNmeSxieT0iSXNsYW5kIiwgYWxsLng9VFJVRSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJBUiIgJiBmWWVhciA+IDI1KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJDRSIgJiBmWWVhciA+IDI1KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJEUyIgJiBmWWVhciA+IDE4KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJGUiIgJiBmWWVhciA+IDExKSklPiUgbXV0YXRlKEJpcnRoWWVhciA9IGZZZWFyICsgZm91bmRlcnllYXIpICU+JSBncm91cF9ieShJc2xhbmQsQmlydGhZZWFyKSAlPiUgc3VtbWFyaXNlKFJpZ2h0VGFyc3VzID0gbWVhbihSaWdodFRhcnN1cywgbmEucm09VFJVRSksIHN0ZC5lcnJvciA9IG1lYW4oc3RkLmVycm9yLCBuYS5ybT1UUlVFKSkKCiNwbG90dGluZyB0aGUgbW9kZWwgKHNob3duIGFzIGdnYXJyYW5nZSBiZWxvdykKSVJUbW9kIDwtIGdncGxvdChJUlRsbWVyZGF0YTIsIGFlcyh4ID0gQmlydGhZZWFyLCB5ID0gUmlnaHRUYXJzdXMsIGZpbGwgPSBJc2xhbmQpKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IEFERF9tZWFuLCBtYXBwaW5nPWFlcyh4PUJpcnRoWWVhcix5PVJpZ2h0VGFyc3VzLGNvbG91cj1Jc2xhbmQpLCBzaXplID0gMikgKwogIGdlb21fZXJyb3JiYXIoZGF0YT1BRERfbWVhbixhZXMoeW1pbj1SaWdodFRhcnN1cy1SVHNkLHltYXg9UmlnaHRUYXJzdXMrUlRzZCwgY29sb3VyPUlzbGFuZCksYWxwaGE9MC43KSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91ciA9IElzbGFuZCksbWV0aG9kID0gImxvZXNzIiwgc2UgPSBGQUxTRSkgKyAKICBnZW9tX3JpYmJvbihhZXMoeW1pbj1SaWdodFRhcnN1cy1zdGQuZXJyb3IseW1heD1SaWdodFRhcnN1cytzdGQuZXJyb3IpLGFscGhhPTAuNSkgKwogIGxhYnMoeCA9ICJCaXJ0aCBZZWFyIiwgeT0gIlRhcnN1cyBMZW5ndGggKG1tKSIpICsKICB4bGltKDE5OTAsMjAyMikgKwogIHRoZW1lX3R1ZnRlKGJhc2Vfc2l6ZSA9IDE1LCBiYXNlX2ZhbWlseSA9ICJBcmlhbCIpICsgCiAgc2NhbGVfY29sb3JfY29sb3JibGluZCgpICsgc2NhbGVfZmlsbF9jb2xvcmJsaW5kKCkKYGBgCgojIyMgQm9keSBNYXNzCgpgYGB7ciBibSwgbWVzc2FnZT1GQUxTRX0KIyMjIyBCb2R5IE1hc3MgLS0tLQpJQk1sbWVyIDwtIGxtZXIoQm9keU1hc3MgfiAgSXNsYW5kKmZZZWFyICsgU2V4ICArICgxfE9ic2VydmVyKSArICgxfEFnZWNsYXNzKSArICgxfEJpcmRJRCksIGRhdGEgPSBBRERfSSkKc3VtbWFyeShJQk1sbWVyKQoKI3ByZWRpY3RpbmcgdGhlIG1vZGVsCklCTWxtZXJkYXRhIDwtIGdncHJlZGljdChJQk1sbWVyLHRlcm1zPWMoImZZZWFyIFthbGxdIiwiSXNsYW5kIiwiU2V4IikpICU+JSByZW5hbWUoZlllYXI9eCxCb2R5TWFzcz1wcmVkaWN0ZWQsSXNsYW5kPWdyb3VwLFNleD1mYWNldCkKSUJNbG1lcmRhdGEyIDwtIG1lcmdlKElCTWxtZXJkYXRhLElzZnksYnk9IklzbGFuZCIsIGFsbC54PVRSVUUpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiQVIiICYgZlllYXIgPiAyNSkpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiQ0UiICYgZlllYXIgPiAyNSkpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiRFMiICYgZlllYXIgPiAxOCkpICU+JSBmaWx0ZXIoIShJc2xhbmQ9PSAiRlIiICYgZlllYXIgPiAxMSkpJT4lIG11dGF0ZShCaXJ0aFllYXIgPSBmWWVhciArIGZvdW5kZXJ5ZWFyKSAgJT4lIGdyb3VwX2J5KElzbGFuZCxCaXJ0aFllYXIpICU+JSBzdW1tYXJpc2UoQm9keU1hc3MgPSBtZWFuKEJvZHlNYXNzLCBuYS5ybT1UUlVFKSwgc3RkLmVycm9yID0gbWVhbihzdGQuZXJyb3IsIG5hLnJtPVRSVUUpKQoKI3Bsb3R0aW5nIHRoZSBtb2RlbApJQk1tb2QgPC0gZ2dwbG90KElCTWxtZXJkYXRhMiwgYWVzKHggPSBCaXJ0aFllYXIsIHkgPSBCb2R5TWFzcywgZmlsbCA9IElzbGFuZCkpICsgCiAgZ2VvbV9wb2ludChkYXRhID0gQUREX21lYW4sIG1hcHBpbmc9YWVzKHg9QmlydGhZZWFyLHk9Qm9keU1hc3MsY29sb3VyPUlzbGFuZCksIHNpemUgPSAyKSArCiAgZ2VvbV9lcnJvcmJhcihkYXRhPUFERF9tZWFuLGFlcyh5bWluPUJvZHlNYXNzLUJNc2QseW1heD1Cb2R5TWFzcytCTXNkLCBjb2xvdXI9SXNsYW5kKSxhbHBoYT0wLjcpICsKICBnZW9tX3Ntb290aChhZXMoY29sb3VyID0gSXNsYW5kKSxtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArIAogIGdlb21fcmliYm9uKGFlcyh5bWluPUJvZHlNYXNzLXN0ZC5lcnJvcix5bWF4PUJvZHlNYXNzK3N0ZC5lcnJvciksYWxwaGE9MC41KSArCiAgbGFicyh4ID0gIkJpcnRoIFllYXIiLCB5PSAiQm9keSBNYXNzIChnKSIpICsKICB4bGltKDE5OTAsMjAyMikgKwogIHRoZW1lX3R1ZnRlKGJhc2Vfc2l6ZSA9IDE1LCBiYXNlX2ZhbWlseSA9ICJBcmlhbCIpICsgCiAgc2NhbGVfY29sb3JfY29sb3JibGluZCgpICsgc2NhbGVfZmlsbF9jb2xvcmJsaW5kKCkKCmBgYAoKIyMjIFdpbmcgTGVuZ3RoCgpgYGB7ciB3bCwgbWVzc2FnZT1GQUxTRX0KIyMjIyBXaW5nIExlbmd0aCAtLS0tCklXTGxtZXIgPC0gbG1lcihXaW5nTGVuZ3RoIH4gIElzbGFuZCpmWWVhciArIFNleCArICgxfE9ic2VydmVyKSArICgxfEFnZWNsYXNzKSArICgxfEJpcmRJRCksIGRhdGEgPSBBRERfSSkKc3VtbWFyeShJV0xsbWVyKQoKI3ByZWRpY3RpbmcgdGhlIG1vZGVsCklXTGxtZXJkYXRhIDwtIGdncHJlZGljdChJV0xsbWVyLHRlcm1zPWMoImZZZWFyIFthbGxdIiwiSXNsYW5kIiwiU2V4IikpICU+JSByZW5hbWUoZlllYXI9eCxXaW5nTGVuZ3RoPXByZWRpY3RlZCxJc2xhbmQ9Z3JvdXAsU2V4PWZhY2V0KQpJV0xsbWVyZGF0YTIgPC0gbWVyZ2UoSVdMbG1lcmRhdGEsSXNmeSxieT0iSXNsYW5kIiwgYWxsLng9VFJVRSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJBUiIgJiBmWWVhciA+IDI1KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJDRSIgJiBmWWVhciA+IDI1KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJEUyIgJiBmWWVhciA+IDE4KSkgJT4lIGZpbHRlcighKElzbGFuZD09ICJGUiIgJiBmWWVhciA+IDExKSkgJT4lIG11dGF0ZShCaXJ0aFllYXIgPSBmWWVhciArIGZvdW5kZXJ5ZWFyKSAlPiUgZ3JvdXBfYnkoSXNsYW5kLEJpcnRoWWVhciklPiUgc3VtbWFyaXNlKFdpbmdMZW5ndGggPSBtZWFuKFdpbmdMZW5ndGgsIG5hLnJtPVRSVUUpLCBzdGQuZXJyb3IgPSBtZWFuKHN0ZC5lcnJvciwgbmEucm09VFJVRSkpCgojcGxvdHRpbmcgdGhlIG1vZGVsCklXTG1vZCA8LSBnZ3Bsb3QoSVdMbG1lcmRhdGEyLCBhZXMoeCA9IEJpcnRoWWVhciwgeSA9IFdpbmdMZW5ndGgsIGZpbGwgPSBJc2xhbmQpKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IEFERF9tZWFuLCBtYXBwaW5nPWFlcyh4PUJpcnRoWWVhcix5PVdpbmdMZW5ndGgsY29sb3VyPUlzbGFuZCksIHNpemUgPSAyKSArCiAgZ2VvbV9lcnJvcmJhcihkYXRhPUFERF9tZWFuLGFlcyh5bWluPVdpbmdMZW5ndGgtV0xzZCx5bWF4PVdpbmdMZW5ndGgrV0xzZCwgY29sb3VyPUlzbGFuZCksYWxwaGE9MC43KSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91ciA9IElzbGFuZCksbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKyAKICBnZW9tX3JpYmJvbihhZXMoeW1pbj1XaW5nTGVuZ3RoLXN0ZC5lcnJvcix5bWF4PVdpbmdMZW5ndGgrc3RkLmVycm9yKSxhbHBoYT0wLjUpICsKICBsYWJzKHggPSAiQmlydGggWWVhciIsIHk9ICJXaW5nIExlbmd0aCAobW0pIikgKwogIHhsaW0oMTk5MCwyMDIyKSArCiAgdGhlbWVfdHVmdGUoYmFzZV9zaXplID0gMTUsIGJhc2VfZmFtaWx5ID0gIkFyaWFsIikgKyAKICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKCkgKyBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKQoKYGBgCgojIyMgSGVhZCArIEJpbGwgTGVuZ3RoCgpgYGB7ciBoYiwgbWVzc2FnZT1GQUxTRX0KIyMjIyBIZWFkICsgQmlsbCAtLS0tCklIQmxtZXIgPC0gbG1lcihIZWFkQmlsbCB+ICBJc2xhbmQqZlllYXIgKyBTZXggICsgKDF8T2JzZXJ2ZXIpICsgKDF8QWdlY2xhc3MpICsgKDF8QmlyZElEKSwgZGF0YSA9IEFERF9JKQpzdW1tYXJ5KElIQmxtZXIpCgojcHJlZGljdGluZyB0aGUgbW9kZWwKSUhCbG1lcmRhdGEgPC0gZ2dwcmVkaWN0KElIQmxtZXIsdGVybXM9YygiZlllYXIgW2FsbF0iLCJJc2xhbmQiLCJTZXgiKSkgJT4lIHJlbmFtZShmWWVhcj14LEhlYWRCaWxsPXByZWRpY3RlZCxJc2xhbmQ9Z3JvdXAsU2V4RXN0aW1hdGU9ZmFjZXQpCklIQmxtZXJkYXRhMiA8LSBtZXJnZShJSEJsbWVyZGF0YSxJc2Z5LGJ5PSJJc2xhbmQiLCBhbGwueD1UUlVFKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkFSIiAmIGZZZWFyID4gMjIpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkNFIiAmIGZZZWFyID4gMjUpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkRTIiAmIGZZZWFyID4gMTgpKSAlPiUgZmlsdGVyKCEoSXNsYW5kPT0gIkZSIiAmIGZZZWFyID4gMTEpKSU+JSBtdXRhdGUoQmlydGhZZWFyID0gZlllYXIgKyBmb3VuZGVyeWVhciklPiUgZ3JvdXBfYnkoSXNsYW5kLEJpcnRoWWVhciklPiUgc3VtbWFyaXNlKEhlYWRCaWxsID0gbWVhbihIZWFkQmlsbCwgbmEucm09VFJVRSksIHN0ZC5lcnJvciA9IG1lYW4oc3RkLmVycm9yLCBuYS5ybT1UUlVFKSkKCiNwbG90dGluZyB0aGUgbW9kZWwKSUhCbW9kIDwtIGdncGxvdChJSEJsbWVyZGF0YTIsIGFlcyh4ID0gQmlydGhZZWFyLCB5ID0gSGVhZEJpbGwsIGZpbGwgPSBJc2xhbmQpKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IEFERF9tZWFuLCBtYXBwaW5nPWFlcyh4PUJpcnRoWWVhcix5PUhlYWRCaWxsLGNvbG91cj1Jc2xhbmQpLCBzaXplID0gMikgKwogIGdlb21fZXJyb3JiYXIoZGF0YT1BRERfbWVhbixhZXMoeW1pbj1IZWFkQmlsbC1IQnNkLHltYXg9SGVhZEJpbGwrSEJzZCwgY29sb3VyPUlzbGFuZCksYWxwaGE9MC43KSArCiAgZ2VvbV9zbW9vdGgoYWVzKGNvbG91ciA9IElzbGFuZCksbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKyAKICBnZW9tX3JpYmJvbihhZXMoeW1pbj1IZWFkQmlsbC1zdGQuZXJyb3IseW1heD1IZWFkQmlsbCtzdGQuZXJyb3IpLGFscGhhPTAuMjUpICsKICBsYWJzKHggPSAiQmlydGggWWVhciIsIHk9ICJIZWFkICsgQmlsbCBMZW5ndGggKG1tKSIpICsKICB4bGltKDE5OTAsMjAyMikgKwogIHRoZW1lX3R1ZnRlKGJhc2Vfc2l6ZSA9IDE1LCBiYXNlX2ZhbWlseSA9ICJBcmlhbCIpICsgCiAgc2NhbGVfY29sb3JfY29sb3JibGluZCgpICsgc2NhbGVfZmlsbF9jb2xvcmJsaW5kKCkKYGBgCgojIyBBcnJhbmdlIGFuZCBwbG90CgpgYGB7ciBpc2xhbmQgcGxvdCwgd2FybmluZz1GQUxTRSwgZmlnLndpZHRoPTEwLGZpZy5oZWlnaHQ9MTB9Ckltb2RzIDwtIGdnYXJyYW5nZShJUlRtb2QsSUJNbW9kLElXTG1vZCxJSEJtb2QsIGNvbW1vbi5sZWdlbmQ9VFJVRSwgbGFiZWxzID0gYygiQSIsIkIiLCJDIiwiRCIpKQpJbW9kcwpgYGAKCiMgTGlmZXNwYW4gYW5kIFJlcHJvZHVjdGlvbgoKIyMgUHJlcGFyaW5nIGRhdGEKCmBgYHtyIGZpdCBkYXRhfQojIG1ha2UgYSBub24tcmVkdW5kYW50IGRhdGEgc2V0IGZvciBsaWZlc3BhbiBhbmQgcmVwcm9kdWN0aW9uCkFERF9SZWFsIDwtIEFERF9JICU+JSBmaWx0ZXIoSXNsYW5kID09ICJDTiIpICU+JSBncm91cF9ieShCaXJkSUQpICU+JSBtdXRhdGUoYWNyb3NzKGMoUmlnaHRUYXJzdXMsQm9keU1hc3MsV2luZ0xlbmd0aCxIZWFkQmlsbCksbWVhbiwgbmEucm09VFJVRSkpICU+JSBmaWx0ZXIoIWR1cGxpY2F0ZWQoQmlyZElEKSkgJT4lIHNlbGVjdChSaWdodFRhcnN1cyxCb2R5TWFzcyxXaW5nTGVuZ3RoLEhlYWRCaWxsLEJpcmRJRCxTZXhFc3RpbWF0ZSxCaXJ0aFllYXIsTGlmZXNwYW4sU3VydlN0YXR1cyxSZXByb2R1Y3RpdmVPdXRwdXQpICU+JSBtdXRhdGUoU2V4RXN0aW1hdGUgPSBhcy5mYWN0b3IoU2V4RXN0aW1hdGUpKQojIGZpbHRlciBmb3IgbWlzc2luZyB2YWx1ZXMKQUREX3RpZHkgPC0gQUREX1JlYWwgJT4lIGZpbHRlcighaXMubmEoUmlnaHRUYXJzdXMpICYgIWlzLm5hKEJvZHlNYXNzKSAgJiAhaXMubmEoV2luZ0xlbmd0aCkgICYgIWlzLm5hKEhlYWRCaWxsKSAmICFpcy5uYShTZXhFc3RpbWF0ZSkgICYgIWlzLm5hKExpZmVzcGFuKSApICU+JSBtdXRhdGUoQm9keUNvbmRpdGlvbiA9IEJvZHlNYXNzL1JpZ2h0VGFyc3VzKSAlPiUgbXV0YXRlKFNleEVzdGltYXRlID0gYXMuZmFjdG9yKFNleEVzdGltYXRlKSkKYGBgCgojIyBTdXJ2aXZhbCBhbmFseXNpcyB3aXRoIGNveG1lCgojIyMgTW9kZWwgY29tcGFyaXNvbnMKCmBgYHtyIGNveG1lfQojIyNMaWZlc3BhbiBhbmFseXNpcyB3aXRoIGNveG1lLS0tLQoKbHNjb3gwIDwtIGNveG1lKFN1cnYoTGlmZXNwYW4sU3VydlN0YXR1cykgfiBSaWdodFRhcnN1cysgQm9keU1hc3MgKyBXaW5nTGVuZ3RoICsgSGVhZEJpbGwgK1NleEVzdGltYXRlICsgKDF8QmlydGhZZWFyKSwgZGF0YT0gQUREX3RpZHkpCmxzY294MSA8LSBjb3htZShTdXJ2KExpZmVzcGFuLFN1cnZTdGF0dXMpIH4gUmlnaHRUYXJzdXMrIHBvbHkoQm9keU1hc3MsMikgKyBXaW5nTGVuZ3RoICsgSGVhZEJpbGwgK1NleEVzdGltYXRlICsgKDF8QmlydGhZZWFyKSwgZGF0YT0gQUREX3RpZHkpCmxzY294MiA8LSBjb3htZShTdXJ2KExpZmVzcGFuLFN1cnZTdGF0dXMpIH4gUmlnaHRUYXJzdXMqcG9seShCb2R5TWFzcywyKSArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCArU2V4RXN0aW1hdGUgKyAoMXxCaXJ0aFllYXIpLCBkYXRhPSBBRERfdGlkeSkKbHNjb3gzIDwtIGNveG1lKFN1cnYoTGlmZXNwYW4sU3VydlN0YXR1cykgfiBwb2x5KEJvZHlDb25kaXRpb24sMikgKyBXaW5nTGVuZ3RoICsgSGVhZEJpbGwgK1NleEVzdGltYXRlICsgKDF8QmlydGhZZWFyKSwgZGF0YT0gQUREX3RpZHkpCmxzY294NCA8LSBjb3htZShTdXJ2KExpZmVzcGFuLFN1cnZTdGF0dXMpIH4gUmlnaHRUYXJzdXMrIHBvbHkoQm9keU1hc3MsMikqU2V4RXN0aW1hdGUgKyBXaW5nTGVuZ3RoICsgSGVhZEJpbGwgKyAoMXxCaXJ0aFllYXIpLCBkYXRhPSBBRERfdGlkeSkKCkFJQyhsc2NveDAsbHNjb3gxLGxzY294Mixsc2NveDMsbHNjb3g0KSAjIGxzY294NCBiZXN0CkJJQyhsc2NveDAsbHNjb3gxLGxzY294Mixsc2NveDMsbHNjb3g0KSAjIGxzY294NCBiZXN0CiMgbHNjb3g0IHdhcyBzZWxlY3RlZCBiYXNlZCBvbiB0aGUgYmVzdCBBSUMgYW5kIEJJQyB2YWx1ZXMKCmxzY294NApgYGAKCiMjIyBQcmVkaWN0aW5nIGFuZCBwbG90dGluZyBjb3htZQoKYGBge3IgY294bWUgcHJlZGljdH0KIyMjI3ByZWRpY3QgbGlmZXNwYW4tLS0tCkFERF9yb3VuZCA8LSBBRERfUmVhbCAlPiVtdXRhdGUoYWNyb3NzKGMoUmlnaHRUYXJzdXMsIEJvZHlNYXNzLCBIZWFkQmlsbCwgV2luZ0xlbmd0aCksIHJvdW5kLCAwKSkgJT4lIGRpc3RpbmN0KFJpZ2h0VGFyc3VzLCBCb2R5TWFzcywgSGVhZEJpbGwsIFdpbmdMZW5ndGgsU2V4RXN0aW1hdGUpICU+JSBmaWx0ZXIoIWlzLm5hKFJpZ2h0VGFyc3VzKSAmICFpcy5uYShCb2R5TWFzcykgICYgIWlzLm5hKFdpbmdMZW5ndGgpICAmICFpcy5uYShIZWFkQmlsbCkgJiAhaXMubmEoU2V4RXN0aW1hdGUpKQpBRERfZW5kIDwtIGJpbmRfcm93cyhBRERfdGlkeSxBRERfcm91bmQpCnJzIDwtIHByZWRpY3RfY294bWUobHNjb3g0LG5ld2RhdGEgPSBBRERfZW5kLHR5cGU9InJpc2siLCBzZS5maXQ9VFJVRSkKcnNlbmQgPC0gQUREX2VuZCAlPiUgYWRkX2NvbHVtbnMocnIgPSBycyRmaXRbLDFdLCBzZS5maXQgPSBycyRzZS5maXRbLDFdKQpBRERfdGFpbCA8LSByc2VuZCAlPiUgdGFpbChucm93KEFERF9yb3VuZCkpICU+JSBtdXRhdGUoU2V4RXN0aW1hdGUgPSBhcy5mYWN0b3IoU2V4RXN0aW1hdGUpKSAlPiUgZ3JvdXBfYnkoQm9keU1hc3MsU2V4RXN0aW1hdGUpICU+JSBzdW1tYXJpc2UobWVhbl9ycj1tZWFuKHJyKSxtZWFuX3NlLmZpdD1tZWFuKHNlLmZpdCkpCgojIHBsb3R0aW5nIGNveG1lCmNveG1lcGxvdCA8LSBnZ3Bsb3QoQUREX3RhaWwsYWVzKHg9Qm9keU1hc3MseT1tZWFuX3JyKSkgKyAKICBnZW9tX2xpbmUoYWVzKGNvbG91cj1TZXhFc3RpbWF0ZSkpICsKICBnZW9tX3JpYmJvbihhZXMoZmlsbD1TZXhFc3RpbWF0ZSx5bWluPW1lYW5fcnItbWVhbl9zZS5maXQseW1heD1tZWFuX3JyK21lYW5fc2UuZml0KSwgYWxwaGEgPSAwLjI1KSArIAogIGxhYnMoeCA9ICJCb2R5IE1hc3MgKGcpIiwgeSA9ICJNb3J0YWxpdHkgUmlzayBTY29yZSIpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGU9IlNleCIpLCBjb2xvdXI9Z3VpZGVfbGVnZW5kKHRpdGxlPSJTZXgiKSkgKwogIHRoZW1lX3R1ZnRlKGJhc2Vfc2l6ZSA9IDE1LCBiYXNlX2ZhbWlseSA9ICJBcmlhbCIpICsgCiAgc2NhbGVfY29sb3JfY29sb3JibGluZChsYWJlbHMgPSBjKCJGZW1hbGUiLCAiTWFsZSIpKSArCiAgc2NhbGVfZmlsbF9jb2xvcmJsaW5kKGxhYmVscyA9IGMoIkZlbWFsZSIsICJNYWxlIikpCmBgYAoKIyMgUmVwcm9kdWN0aXZlIE91dHB1dCB1c2luZyBHTE0KCiMjIyBNb2RlbCBjb21wYXJpc29ucwoKYGBge3IgZ2xtfQojIyNSZXByb2R1Y3Rpb24gZ2xtLS0tLQpST2dsbUYgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IFJpZ2h0VGFyc3VzKyBCb2R5TWFzcyArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCAgLGRhdGEgPSBBRERfdGlkeSwgZmFtaWx5ID0gInBvaXNzb24iKQpST2dsbVIgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IHBvbHkoTGlmZXNwYW4sMikgKyBTZXhFc3RpbWF0ZSArIEJpcnRoWWVhcixkYXRhID0gQUREX3RpZHksIGZhbWlseSA9ICJwb2lzc29uIikKUk9nbG0wIDwtIGdsbShSZXByb2R1Y3RpdmVPdXRwdXQgfiBSaWdodFRhcnN1cysgQm9keU1hc3MgKyBXaW5nTGVuZ3RoICsgSGVhZEJpbGwgICsgTGlmZXNwYW4gKyBTZXhFc3RpbWF0ZSArIEJpcnRoWWVhcixkYXRhID0gQUREX3RpZHksIGZhbWlseSA9ICJwb2lzc29uIikKUk9nbG0xIDwtIGdsbShSZXByb2R1Y3RpdmVPdXRwdXQgfiBSaWdodFRhcnN1cysgQm9keU1hc3MgKyBXaW5nTGVuZ3RoICArIEhlYWRCaWxsICArIHBvbHkoTGlmZXNwYW4sMikgKyBTZXhFc3RpbWF0ZSArIEJpcnRoWWVhcixkYXRhID0gQUREX3RpZHksIGZhbWlseSA9ICJwb2lzc29uIikKUk9nbG0yIDwtIGdsbShSZXByb2R1Y3RpdmVPdXRwdXQgfiBwb2x5KFJpZ2h0VGFyc3VzLDIpKyBCb2R5TWFzcyArIFdpbmdMZW5ndGggKyBIZWFkQmlsbCAgKyBwb2x5KExpZmVzcGFuLDIpICsgU2V4RXN0aW1hdGUgKyBCaXJ0aFllYXIsZGF0YSA9IEFERF90aWR5LCBmYW1pbHkgPSAicG9pc3NvbiIpClJPZ2xtMyA8LSBnbG0oUmVwcm9kdWN0aXZlT3V0cHV0IH4gUmlnaHRUYXJzdXMrIHBvbHkoQm9keU1hc3MsMikgKyBXaW5nTGVuZ3RoICsgSGVhZEJpbGwgICsgcG9seShMaWZlc3BhbiwyKSArIFNleEVzdGltYXRlICsgQmlydGhZZWFyLGRhdGEgPSBBRERfdGlkeSwgZmFtaWx5ID0gInBvaXNzb24iKQpST2dsbTQgPC0gZ2xtKFJlcHJvZHVjdGl2ZU91dHB1dCB+IFJpZ2h0VGFyc3VzKyBCb2R5TWFzcyArIHBvbHkoV2luZ0xlbmd0aCwyKSArIEhlYWRCaWxsICArIHBvbHkoTGlmZXNwYW4sMikgKyBTZXhFc3RpbWF0ZSArIEJpcnRoWWVhcixkYXRhID0gQUREX3RpZHksIGZhbWlseSA9ICJwb2lzc29uIikKUk9nbG01IDwtIGdsbShSZXByb2R1Y3RpdmVPdXRwdXQgfiBSaWdodFRhcnN1cysgQm9keU1hc3MgKyBXaW5nTGVuZ3RoICsgcG9seShIZWFkQmlsbCwyKSAgKyBwb2x5KExpZmVzcGFuLDIpICsgU2V4RXN0aW1hdGUgKyBCaXJ0aFllYXIsZGF0YSA9IEFERF90aWR5LCBmYW1pbHkgPSAicG9pc3NvbiIpCgpBSUMoUk9nbG1GLFJPZ2xtUixST2dsbTAsUk9nbG0xLFJPZ2xtMixST2dsbTMsUk9nbG00LFJPZ2xtNSkgIyBST2dsbTQgc2xpZ2h0bHkgYmV0dGVyIHRoYW4gUk9nbG0xIHNlY29uZApCSUMoUk9nbG1GLFJPZ2xtUixST2dsbTAsUk9nbG0xLFJPZ2xtMixST2dsbTMsUk9nbG00LFJPZ2xtNSkgIyBST2dsbTEgYmVzdCAKI1JPZ2xtMSB3YXMgc2VsZWN0ZWQgYmFzZWQgb24gQUlDIGFuZCBCSUMgc2NvcmVzCnZpZihST2dsbTEpCgpzdW1tYXJ5KFJPZ2xtMSkKYGBgCgojIyMgUHJlZGljdGluZyBhbmQgcGxvdHRpbmcgR0xNCgpgYGB7ciBnbG0gcHJlZGljdH0KIyMjI3ByZWRpY3QgcmVwcm9kdWN0aW9uLS0tLQojIGdyb3VwaW5nIHZhcmlhYmxlcyBmb3IgZ2xtIHBsb3QKUk9wbG90ZGF0YSA8LSBBRERfdGlkeSAlPiUgbXV0YXRlKEJvZHlNYXNzID0gY2FzZV93aGVuKEJvZHlNYXNzID4gMTYuNSB+ICIxNi41IiwgQm9keU1hc3MgPCAxNC41IH4gIjE0LjUiLEJvZHlNYXNzIDwgMTYuNSAmIEJvZHlNYXNzID4gMTQuNSB+ICIxNS41IikpICU+JSBmaWx0ZXIoIWlzLm5hKEJvZHlNYXNzKSkKCiMgcHJlZGljdGluZyBnbG0gClJPZ2xtZGF0IDwtIGdncHJlZGljdChST2dsbTEsIHRlcm1zID0gYygiTGlmZXNwYW4iLCJCb2R5TWFzcyIpKSAlPiUgcmVuYW1lKExpZmVzcGFuPXgsUmVwcm9kdWN0aXZlT3V0cHV0PXByZWRpY3RlZCxCb2R5TWFzcz1ncm91cCkKCiNwbG90dGluZyBnbG0KUk9nbG1wbG90IDwtIGdncGxvdChST2dsbWRhdCwgYWVzKHg9TGlmZXNwYW4seT1SZXByb2R1Y3RpdmVPdXRwdXQpKSArIAogIGdlb21fcG9pbnQoZGF0YSA9IFJPcGxvdGRhdGEsIG1hcHBpbmc9YWVzKHg9TGlmZXNwYW4seT1SZXByb2R1Y3RpdmVPdXRwdXQsY29sb3VyPUJvZHlNYXNzKSxwb3NpdGlvbj0iaml0dGVyIikgKwogIGdlb21fc21vb3RoKGFlcyhjb2xvdXI9Qm9keU1hc3MpLCBzZSA9IEZBTFNFKSArIAogIGdlb21fcmliYm9uKGFlcyh5bWluPWNvbmYubG93LHltYXg9Y29uZi5oaWdoLGZpbGw9Qm9keU1hc3MpLCBhbHBoYSA9IDAuMjUpICsKICBsYWJzKHggPSAiTGlmZXNwYW4gKHllYXJzKSIsIHk9ICJUb3RhbCBOdW1iZXIgb2YgT2Zmc3ByaW5nIikgKwogIHRoZW1lX3R1ZnRlKGJhc2Vfc2l6ZSA9IDE1LCBiYXNlX2ZhbWlseSA9ICJBcmlhbCIpICsKICBzY2FsZV9jb2xvcl9jb2xvcmJsaW5kKCkgKyBzY2FsZV9maWxsX2NvbG9yYmxpbmQoKQpgYGAKCiMjIEFycmFuZ2UgYW5kIHBsb3QKCmBgYHtyIGZpdHBsb3RzLCB3YXJuaW5nPUZBTFNFLCBmaWcud2lkdGg9MTAsZmlnLmhlaWdodD0xMH0KZml0cGxvdCA8LSBnZ2FycmFuZ2UoY294bWVwbG90LFJPZ2xtcGxvdCwgIGxhYmVscyA9IGMoIkEiLCJCIikpCmZpdHBsb3QKYGBgCgpUaW1lIHRha2VuIHRvIHJ1biB0aGUgd2hvbGUgc2NyaXB0CgpgYGB7ciB0aW1lLCBlY2hvPUZBTFNFfQplbmRfdGltZTwtU3lzLnRpbWUoKQoKcm91bmQoKGVuZF90aW1lIC0gc3RhcnRfdGltZSksIDMpCmBgYAoKIyBBY2tub3dsZWRnbWVudAoKVGhhbmsgeW91IGZvciBnb2luZyB0aHJvdWdoIHRoZSBjb2RlIGFuZCBzdXBwb3J0aW5nIG9wZW4gcmVzZWFyY2guIFRoaXMgcGFwZXIgd291bGQgbm90IGhhdmUgYmVlbiBwb3NzaWJsZSB3aXRob3V0IGFsbCBhdXRob3JzIGNvbnRyaWJ1dGluZyB0b3dhcmRzIGl0LiBNYXNzaXZlIHRoYW5rcyB0byBldmVyeW9uZSB0aGF0IGhhcyBzaGFyZWQgdGhlaXIgZXhjaXRlbWVudCBmb3IgdGhpcyBwYXBlci4KCjxwIGFsaWduPSJjZW50ZXIiPgohW10oSW1hZ2VzL2NodWVubG9nb3RyYW5zcGFyZW50aGQucG5nKXt3aWR0aD0iMzAlIn0KPC9wPgo=